%%--------------------------------------------------------------------
%% Author: <vjache>
%% Created: 17.03.2009
%% Description: TODO: Add description to merge_sort
%%--------------------------------------------------------------------
-module(iter_join_cprod).

%%--------------------------------------------------------------------
%% Include files
%%--------------------------------------------------------------------
-include_lib("eunit/include/eunit.hrl").

-include("../../include/iter.hrl").
%%--------------------------------------------------------------------
%% Exported Functions
%%--------------------------------------------------------------------
-export([
		 new/2,
		 open/1,
		 next/1,
		 close/1,
		 all/1
		 ]).

%%--------------------------------------------------------------------
%% API Functions
%%--------------------------------------------------------------------

new(Iter1,Iter2) ->
	new_(Iter1,
		 iter_mapper:new(
		   Iter2,
		   fun(Item)->
				   [Item]
		   end)).

new_(Iter1,Iter2) ->
	iter:from_module(
	  ?MODULE, 
	  { Iter1,Iter2}).

all([]=_IterList) ->
	iter:empty();
all(IterList) ->
	lists:foldr(
	  fun(Iter,AccIn)->
			  new_(Iter,AccIn)
	  end, 
	  iter:single([]),IterList).

open({IterLeft,IterRight}) ->
	StateLeft=iter:open(IterLeft),
	{iter:next(StateLeft),need_open,IterRight}.

next({{_State1,?EOF},need_open,_Iter2}=S) ->
	{S,?EOF};
next({Left,need_open,IterRight}=_S) ->
	StateRight=iter:open(IterRight),
	next({Left,StateRight,IterRight});
next({{StateLeft,CurrLeftItem}=Left,StateRight,IterRight}=_S) ->
	{StateRightNew,RightItem}=iter:next(StateRight),
	case RightItem of
		?EOF ->
			ok=iter:close(StateRightNew),
			next({iter:next(StateLeft),need_open,IterRight});
		_ ->
			{{Left,StateRightNew,IterRight},[CurrLeftItem|RightItem]}
	end.


close({{StateLeft,_CurrLeftItem},need_open,_IterRight}) ->
	ok=iter:close(StateLeft);
close({{StateLeft,_CurrLeftItem},StateRight,_IterRight}) ->
	ok=iter:close(StateRight),
	ok=iter:close(StateLeft).

%%--------------------------------------------------------------------
%% eunit test functions
%%--------------------------------------------------------------------
basic_test() ->
	TestData1=[1,2,3],
	TestData2=[a,b,c],
	I=new(iter:from_list(TestData1),iter:from_list(TestData2)),
	iter:print(I).
big_test() ->
	TestData1=lists:seq(1, 1000),
	TestData2=[q,w,e,r,t,y,u,i,o,p,a,s,d,f,g,h,j,k,l,z,x,c,v,b,n,m],
	I=new(iter:from_list(TestData1),iter:from_list(TestData2)),
	iter:to_list(I).
all_test() ->
	TestData1=[
			   L1=[a,b,c],
			   L2=[x,y,z],
			   L3=[1,2,3],
			   L4=[a1,b2,c3],
			   L5=[x1,y2,z3],
			   L6=[11,22,33]],
	ExpectedResult=[[E1,E2,E3,E4,E5,E6]||
					E1<-L1,
					E2<-L2,
					E3<-L3,
					E4<-L4,
					E5<-L5,
					E6<-L6],
	I=all([iter:from_list(L)||L<-TestData1]),
	?assertEqual(ExpectedResult,iter:to_list(I)),
	iter:to_list(I).
%%--------------------------------------------------------------------
%% Local Functions
%%--------------------------------------------------------------------
